// module-info.java这个模块文件在src下面

//模块描述文件
module hello.world {
	requires java.base; //可不写,任何模块都自动导入java.base
	requires java.xml;
}

/*
其中，module是关键字
后面的hello.world是模块的名称

它的命名规范与包一致。

花括号的requires xxx;表示这个模块需要引用的其他模块名。

除了java.base可以被自动引入外，这里我们引入了一个java.xml的模块。

*/

//当我们使用模块声明了依赖关系后，才能使用引入的模块。

//例如,Main.java代码如下
package com.itranswarp.sample;

// 必须引入java.xml模块后才能使用其中的类
import javax.xml.XMLConstants;

public class Main {
	public static void main(String[] args) {
		Greeting g = new Greeting();
		System.out.println(g.hello(XMLConstants.XML_NS_PREFIX));
	}
}
//如果把requires java.xml;从module-info.java中去掉，编译将报错。可见，模块的重要作用就是声明依赖关系。



//下面,我们用JDK提供的命令行工具来编译并创建模块

/*
首先，我们把工作目录切换到oop-module，在当前目录下编译所有的.java文件，并存放到bin目录下，命令如下：
javac -d bin src/module-info.java src/com/itranswarp/sample/*.java


如果编译成功，现在项目结构如下：

	oop-module
	├── bin
	│   ├── com
	│   │   └── itranswarp
	│   │       └── sample
	│   │           ├── Greeting.class
	│   │           └── Main.class
	│   └── module-info.class
	└── src
	    ├── com
	    │   └── itranswarp
	    │       └── sample
	    │           ├── Greeting.java
	    │           └── Main.java
	    └── module-info.java


注意到src目录下的module-info.java被编译到bin目录下的module-info.class。


下一步,我们需要把bin目录下的所有class文件先打包成jar，在打包的时候，注意传入--main-class参数，让这个jar包能自己定位main方法所在的类：
	jar --create --file hello.jar --main-class com.itranswarp.sample.Main -C bin .


现在我们就在当前目录下得到了hello.jar这个jar包，它和普通jar包并无区别，可以直接使用命令java -jar hello.jar来运行它。

但是我们的目标是创建模块.
所以，继续使用JDK自带的jmod命令把一个jar包转换成模块：
	jmod create --class-path hello.jar hello.jmod

于是，在当前目录下我们又得到了hello.jmod这个模块文件，这就是最后打包出来的传说中的模块！





# 运行模块

要运行一个jar，我们使用java -jar xxx.jar命令。

要运行一个模块，我们只需要指定模块名。试试：
	java --module-path hello.jmod --module hello.world


结果是一个错误：
Error occurred during initialization of boot layer
java.lang.module.FindException: JMOD format not supported at execution time: hello.jmod


原因是.jmod不能被放入--module-path中。换成.jar就没问题了：
$ java --module-path hello.jar --module hello.world
Hello, xml!

那我们辛辛苦苦创建的hello.jmod有什么用？答案是我们可以用它来打包JRE。




#  打包JRE

前面讲了，为了支持模块化，Java 9首先带头把自己的一个巨大无比的rt.jar拆成了几十个.jmod模块，原因就是，运行Java程序的时候，实际上我们用到的JDK模块，并没有那么多。不需要的模块，完全可以删除。

过去发布一个Java应用程序，要运行它，必须下载一个完整的JRE，再运行jar包。而完整的JRE块头很大，有100多M。怎么给JRE瘦身呢？


现在，JRE自身的标准库已经分拆成了模块，只需要带上程序用到的模块，其他的模块就可以被裁剪掉。怎么裁剪JRE呢？并不是说把系统安装的JRE给删掉部分模块，而是“复制”一份JRE，但只带上用到的模块。为此，JDK提供了jlink命令来干这件事。命令如下：

$ jlink --module-path hello.jmod --add-modules java.base,java.xml,hello.world --output jre/



现在，在当前目录下，我们可以找到jre目录，这是一个完整的并且带有我们自己hello.jmod模块的JRE。试试直接运行这个JRE：
$ jre/bin/java --module hello.world
Hello, xml!

要分发我们自己的Java应用程序，只需要把这个jre目录打个包给对方发过去，对方直接运行上述命令即可，既不用下载安装JDK，也不用知道如何配置我们自己的模块，极大地方便了分发和部署。






# 访问权限

前面我们讲过，Java的class访问权限分为public、protected、private和默认的package访问权限。引入模块后，这些访问权限的规则就要稍微做些调整。

确切地说，class的这些访问权限只在一个模块module内有效，模块和模块之间，例如，a模块要访问b模块的某个class，必要条件是b模块明确地导出了可以访问的package(包)。

举个例子：我们编写的Main.java->Main.class调用了module(模块)hello.world中的模块java.xml的一个类javax.xml.XMLConstants，我们之所以能在class Main中直接使用import javax.xml.XMLConstants;这个类，是因为模块的模块java.xml所属的的module-info.java中给予了声明,所以可以直接调用,java.xml内部子模块的导出：

*/
module java.xml {
	exports java.xml;
	exports javax.xml.catalog;
	exports javax.xml.datatype;
	//...
}

/*
只有它声明的导出的包，外部代码才被允许访问。换句话说，如果外部代码想要访问我们的hello.world模块中的com.itranswarp.sample.Greeting类，我们必须将其导出：
*/
module hello.world {
	exports com.itranswarp.sample; //module中声明了exports给哪一个package,那个package必须写入到module中

	requires java.base;
	requires java.xml;
}

// 因此，模块进一步隔离了代码的访问权限。


/* 理论小结
1.Java 9引入的模块目的是为了管理依赖;

2.使用模块可以按需打包JRE;

3.使用模块对class的访问权限有了进一步限制。


操作小结:

Java9之前:
	1.java -cp app.jar:a1.jar:a2.jar:a3.jar com.sample.Main
	(如果漏写了需要的jar,则ClassNotFoundException)


Java9之后
	1.先在src中编写一个module-info.java,内部写明requires哪些子模块(自动requires java.base);同时写明exports给哪些package使用;

	2.使用JDK提供的CommandLine Tool来Compile and Create Module：切换到最高层工作目录,Compile所有的.java文件,并存放到bin目录下.
	命令:
	$javac -d bin src/module-info.java src/com/itranswarp/sample/*.java

	3.编译成功后,bin目录下有所有文件的.class字节码文件,然后把这些.class打包成jar
	$jar --create --file hello.jar --main-class com.itranswarp.sample.Main -C bin .
	(输出文件名:指定main入口:输入文件夹:输出文件夹)
	ps:得到hello.jar这个jar包
	
	4.通过jar包->创建一个模块
	(JDK->CommandLine)
	$jmod create --class-path hello.jar hello.jmod
		(create模式:输入jar包:输出自定义jmod包)

	5.运行模块
	$java --module-path hello.jar --module hello.world
	(运行:jar包:模组文件中の模组依赖名)

	6.自定义打包JRE
	$jlink --module-path hello.jmod --add-modules java.base,java.xml,hello.world --output jre/
	(打包:模块文件:指定加载的模块:输出目录)
		在jre目录下有一个hello.jmod模块的JRE

	7.运行jre
	$ jre/bin/java --module hello.world


*/















